/*
/---------------------------------------------------------------------\
|   This file is part of SAPlink Unit Tests                           |
|                                                                     |
|   SAPlink Unit Tests is free software;                              |
|   you can redistribute it and/or modify                             |
|   it under the terms of the GNU General Public License as published |
|   by the Free Software Foundation; either version 2 of the License, |
|   or (at your option) any later version.                            |
|                                                                     |
|   SAPlink Unit Tests is distributed in the hope that                |
|   it will be useful,                                                |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of    |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
|   GNU General Public License for more details.                      |
|                                                                     |
|   You should have received a copy of the GNU General Public License |
|   along with SAPlink Unit Tests; if not, write to the               |
|   Free Software Foundation, Inc.,                                   |
|   51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA          |
\---------------------------------------------------------------------/
 */

/*
 * Created on Jan 21, 2010
 *
 * Id:       $Id$
 * Revision: $Revision$
 * Modified: $Date$
 *
 * XMLvalidator
 *
 * Code When          Who               What
 * ---- ------------- ----------------- -------------------------------------
 * EP01 Jan 21, 2010  edward@evpnet.com Initial version
 */
package com.evpnet.xmlvalidator;

import java.io.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.ErrorHandler;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import java.util.ArrayList;

public class XMLvalidator {
	private static final String FAILURE = "FAIL";
	private static final String SUCCESS = "OK";
	private static final String UNDEFINED = "UNDEF";

	private ArrayList messages = new ArrayList();
	private String status = UNDEFINED;

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	/**
	 * 
	 * @param msg
	 */
	public void addMessage(String msg) {
		messages.add(msg);
	}

	/**
	 * 
	 * @param index
	 * @return
	 */
	public String getMessage(int index) {
		return (String)messages.get(index);
	}

	/**
	 * 
	 * @return
	 */
	public int getMessageCount() {
		return messages.size();
	}

	/**
	 * 
	 * @param xmlFilename
	 * @param schemaFilename
	 * @return
	 */
	public int run(String xmlFilename, String schemaFilename) {
		DocumentBuilderFactory factory;

		try{
			messages.clear();

			factory = DocumentBuilderFactory.newInstance();
			factory.setValidating(true);

			factory.setAttribute(
					"http://java.sun.com/xml/jaxp/properties/schemaLanguage", 
			"http://www.w3.org/2001/XMLSchema");
			factory.setAttribute(
					"http://java.sun.com/xml/jaxp/properties/schemaSource",
					schemaFilename);

			DocumentBuilder parser = factory.newDocumentBuilder();
			parser.setErrorHandler(new LocalErrorHandler(this));

			parser.parse(xmlFilename);

			setStatus(SUCCESS);
			return 0;
		}
		catch (ParserConfigurationException e){
			setStatus(FAILURE);
			addMessage("ParserConfigurationException:" + e.getMessage());
			return 2;
		}
		catch (SAXException e){
			setStatus(FAILURE);
			addMessage("SAXException:" + e.getMessage());
			return 3;
		}
		catch (IOException e){
			setStatus(FAILURE);
			addMessage("IOException:" + e.getMessage());
			return 4;
		}
		catch (Exception e){
			setStatus(FAILURE);
			addMessage("Exception:" + e.getMessage());
			return 5;
		}
	}

	public static void main(String args[]) {
		if (args.length == 2) {
			XMLvalidator app = new XMLvalidator();
			int rc = app.run(args[0], args[1]);

			System.out.println(app.getStatus());
			for (int i = 0; i < app.getMessageCount(); i++) {
				System.out.println(app.getMessage(i));
			}

			System.exit(rc);
		}
		else {
			System.out.println(FAILURE);
			System.out.println("Usage:");
			System.out.println("XMLvalidator xmlFileName schemaFilename");

			System.exit(100);
		}
	}
}


/**
 * Based on example from http://www.ibm.com/developerworks/library/x-tipeh.html
 * 
 * There will be only one warning, error or fatalError
 */

class LocalErrorHandler implements ErrorHandler {

	private static final String WARNING = "WARNING";
	private static final String ERROR = "ERROR";
	private static final String FATAL = "FATAL";

	private XMLvalidator validator;

	LocalErrorHandler(XMLvalidator validator) {
		this.validator = validator;
	}
	
	private void addMessage(String type, SAXParseException exception) {
		validator.addMessage(
				type +
				" Line:" + 
				exception.getLineNumber() +
				" Column:" + 
				exception.getLineNumber() +
			//	" File:" + 
			//	exception.getSystemId() +
				" Message:" + 
				exception.getMessage()
		);        
	}

	public void warning(SAXParseException exception) throws SAXException {
		addMessage(WARNING, exception);        
		throw new SAXException(WARNING);
	}

	public void error(SAXParseException exception) throws SAXException {
		addMessage(ERROR, exception);        
		throw new SAXException(ERROR);
	}

	public void fatalError(SAXParseException exception) throws SAXException {
		addMessage(FATAL, exception);        
		throw new SAXException(FATAL);
	}
}
